﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.IO.Ports;
using System.Windows.Forms;
using System.Threading;
using BarCode.Module;

namespace BarCode.Common
{
    public class ComUtil
    {
        private static readonly log4net.ILog LogUtil = log4net.LogManager.GetLogger(typeof(ComUtil));


        /// <summary>
        /// 加载监视器串口
        /// </summary>
        /// <param name="ComDevice"></param>
        /// <param name="portName"></param>
        /// <returns></returns>
        public static bool LoadMonitor(SerialPort ComDevice)
        {
            // 获取监视器的相关设值
            string portName = IniFileHelper.getStringValue("System", "Monitor_Port");
            if (string.IsNullOrEmpty(portName))
            {
                MessageUtil.Error("监视器的串口号未设置，请设置后重启程序。");
                return false;
            }

            List<string> portList = new List<string>();
            portList.Add(portName);
            portList.Add("COM3");
            portList.Add("COM4");
            portList.Add("COM5");

            foreach (string tryPort in portList)
            {
                ComDevice.PortName = tryPort;
                ComDevice.BaudRate = 9600;
                ComDevice.Parity = Parity.Even;
                ComDevice.DataBits = 8;
                ComDevice.StopBits = StopBits.One;
                try
                {
                    Application.DoEvents();
                    ComDevice.Open();
                    LogUtil.Error(tryPort + "串口打开成功");
                    // 写入配置文件
                    IniFileHelper.setStringValue("System", "Monitor_Port", tryPort);
                    return true;
                }
                catch (Exception ex)
                {
                    LogUtil.Error(tryPort + "串口打开异常", ex);
                }
            }
            return false;
        }

        /// <summary>
        /// 创建成功指令
        /// </summary>
        /// <param name="stationNo"></param>
        /// <param name="workAmount"></param>
        /// <returns></returns>
        public static string createSuccessCode(string stationNo, int workAmount)
        {
            string headStr1 = "FEFEFE";
            string headStr2 = "680E09";
            string endStr = "16";

            StringBuilder codeContent = new StringBuilder("");
            codeContent.Append(stationNo);
            codeContent.Append("00"); // 错误字符显示
            codeContent.Append(string.Format("{0:X4}", workAmount));            
            codeContent.Append("01"); // 短鸣
            codeContent.Append("00"); // 红灯关
            codeContent.Append("01"); // 绿灯闪烁
            codeContent.Append("00"); // 蓝灯关
            codeContent.Append("00"); // 阀门关
            // 校验和
            string verifyCode = getVerifyCode(headStr2 + codeContent.ToString());
            return headStr1 + headStr2 + codeContent.ToString() + verifyCode + endStr;
        }

        /// <summary>
        /// 创建成功指令并关闭阀门
        /// </summary>
        /// <param name="stationNo"></param>
        /// <param name="workAmount"></param>
        /// <returns></returns>
        public static string createSuccessCodeWithCloseValve(string stationNo, int workAmount)
        {
            string headStr1 = "FEFEFE";
            string headStr2 = "680E09";
            string endStr = "16";

            StringBuilder codeContent = new StringBuilder("");
            codeContent.Append(stationNo);
            codeContent.Append("00"); // 错误字符显示
            codeContent.Append(string.Format("{0:X4}", workAmount));
            codeContent.Append("01"); // 短鸣
            codeContent.Append("00"); // 红灯关
            codeContent.Append("02"); // 绿灯常亮
            codeContent.Append("00"); // 蓝灯关
            codeContent.Append("02"); // 阀门关
            // 校验和
            string verifyCode = getVerifyCode(headStr2 + codeContent.ToString());
            return headStr1 + headStr2 + codeContent.ToString() + verifyCode + endStr;
        }

        /// <summary>
        /// 停止阀门
        /// </summary>
        /// <param name="stationNo"></param>
        /// <param name="workAmount"></param>
        /// <returns></returns>
        public static string createCloseValveCode(string stationNo, int workAmount)
        {
            string headStr1 = "FEFEFE";
            string headStr2 = "680E09";
            string endStr = "16";

            StringBuilder codeContent = new StringBuilder("");
            codeContent.Append(stationNo);
            codeContent.Append("00"); // 错误字符显示
            codeContent.Append(string.Format("{0:X4}", workAmount));
            codeContent.Append("00"); // 短鸣
            codeContent.Append("00"); // 红灯关
            codeContent.Append("00"); // 绿灯闪烁
            codeContent.Append("00"); // 蓝灯关
            codeContent.Append("00"); // 阀门停止
            // 校验和
            string verifyCode = getVerifyCode(headStr2 + codeContent.ToString());
            return headStr1 + headStr2 + codeContent.ToString() + verifyCode + endStr;
        }

        /// <summary>
        /// 创建输入中指令
        /// </summary>
        /// <param name="stationNo"></param>
        /// <param name="workAmount"></param>
        /// <returns></returns>
        public static string createInputingCode(string stationNo, int workAmount)
        {
            string headStr1 = "FEFEFE";
            string headStr2 = "680E09";
            string endStr = "16";

            StringBuilder codeContent = new StringBuilder("");
            codeContent.Append(stationNo);
            codeContent.Append("00"); // 错误字符显示
            codeContent.Append(string.Format("{0:X4}", workAmount));
            codeContent.Append("01"); // 短鸣
            codeContent.Append("00"); // 红灯关
            codeContent.Append("00"); // 绿灯关
            codeContent.Append("02"); // 蓝灯常亮
            codeContent.Append("00"); // 阀门关
            // 校验和
            string verifyCode = getVerifyCode(headStr2 + codeContent.ToString());
            return headStr1 + headStr2 + codeContent.ToString() + verifyCode + endStr;
        }

        /// <summary>
        /// 创建失败指令
        /// </summary>
        /// <param name="stationNo"></param>
        /// <param name="workAmount"></param>
        /// <returns></returns>
        public static string createFailCode(string stationNo, int workAmount)
        {
            string headStr1 = "FEFEFE";
            string headStr2 = "680E09";
            string endStr = "16";

            StringBuilder codeContent = new StringBuilder("");
            codeContent.Append(stationNo);
            codeContent.Append("00"); // 错误字符显示
            codeContent.Append(string.Format("{0:X4}", workAmount));
            codeContent.Append("02"); // 长鸣
            codeContent.Append("02"); // 红灯亮
            codeContent.Append("00"); // 绿灯关
            codeContent.Append("00"); // 蓝灯关
            codeContent.Append("00"); // 阀门关
            // 校验和
            string verifyCode = getVerifyCode(headStr2 + codeContent.ToString());
            return headStr1 + headStr2 + codeContent.ToString() + verifyCode + endStr;
        }

        /// <summary>
        /// 创建停鸣指令
        /// </summary>
        /// <param name="stationNo"></param>
        /// <param name="workAmount"></param>
        /// <returns></returns>
        public static string createStopWarnCode(string stationNo, int workAmount)
        {
            string headStr1 = "FEFEFE";
            string headStr2 = "680E09";
            string endStr = "16";

            StringBuilder codeContent = new StringBuilder("");
            codeContent.Append(stationNo);
            codeContent.Append("00"); // 错误字符显示
            codeContent.Append(string.Format("{0:X4}", workAmount));
            codeContent.Append("00"); // 不鸣
            codeContent.Append("00"); // 红灯关
            codeContent.Append("00"); // 绿灯关
            codeContent.Append("00"); // 蓝灯关
            codeContent.Append("00"); // 阀门关
            // 校验和
            string verifyCode = getVerifyCode(headStr2 + codeContent.ToString());
            return headStr1 + headStr2 + codeContent.ToString() + verifyCode + endStr;
        }

        public static bool sendData(SerialPort ComDevice, string sendCode)
        {
            LogUtil.Info("发送源数据：" + sendCode);
            byte[] sendData = strToHexByte(sendCode);

            if (sendCmd(ComDevice, sendData))
            {
                //读取返回数据
                int waitMillSeconds = 1;
                while (ComDevice.BytesToRead == 0 && waitMillSeconds < 4000)
                {
                    Thread.Sleep(1);
                    Application.DoEvents();
                    waitMillSeconds++;
                }
                Thread.Sleep(50); //50毫秒内数据接收完毕，可根据实际情况调整
                byte[] recData = new byte[ComDevice.BytesToRead];
                ComDevice.Read(recData, 0, recData.Length);
                string recStr = logReceiveData(recData);//输出数据
                return true;
            }
            else
            {
                LogUtil.Error("指令发送失败");
                return false;
            }
            //return true;
        }


        private static string getVerifyCode(string verifySourceStr)
        {

            int verifyResult = 0;
            for (int i = 0; i < verifySourceStr.Length / 2; i++)
            {
                verifyResult += Convert.ToInt32(verifySourceStr.Substring(i * 2, 2), 16);

            }
            string verifyCode = Convert.ToString(verifyResult, 16).ToUpper();
            verifyCode = verifyCode.Substring(verifyCode.Length - 2);
            return verifyCode;
        }

        /// <summary>
        /// 字符串转换16进制字节数组
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] strToHexByte(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0) hexString += " ";
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Replace(" ", ""), 16);
            return returnBytes;
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="data"></param>
        public static bool sendCmd(SerialPort ComDevice, byte[] data)
        {
            Application.DoEvents();
            try
            {
                if (!ComDevice.IsOpen)
                {
                    LogUtil.Error("串口未打开，重新打开");
                    ComDevice.Open();
                }

                try
                {
                    ComDevice.Write(data, 0, data.Length);//发送数据
                    return true;
                }
                catch (Exception ex)
                {
                    LogUtil.Error("发送异常", ex);
                }
            }
            catch (Exception ex)
            {
                LogUtil.Error("异常发生", ex);
            }
            return false;
        }

        /// <summary>
        /// 输出串口接收信息
        /// </summary>
        /// <param name="data"></param>
        private static string logReceiveData(byte[] data)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sb.AppendFormat("{0:x2}" + " ", data[i]);
            }
            LogUtil.Info("串口接收信息：" + sb.ToString().ToUpper());
            return sb.ToString().ToUpper();
        }

    }
}
